In this assignment you will develop your initial concept note into a draft of a full project proposal. Treat this assignment as a “dry run” for developing a proposal for a grant or fellowship application, or for your Ph.D. prospectus.
Your proposal should include at least the following sections and information.
Front matter: Descriptive title, your name, date, reference to “SYS 5581 Time Series & Forecasting, Spring 2021”.
Abstract: A very brief summary of the project.
Introduction
Give a narrative description of the problem you are addressing, and the methods you will use to address it. Provide context:
- What is the question you are attempting to answer?
- Why is this question important? (Who cares?)
- How will you go about attempting to answer this question?
This work addresses the question: Why do people not use probabilistic forecasts for decision-making (???)?
The data and the data-generating process
Describe the data set you will be analyzing, and where it comes from, how it was generated and collected. Identify the source of the data. Give a narrative description of the data-generating process: this piece is critical .
Since these will be time series data: identify the frequency of the data series (e.g., hourly, monthly), and the period of record.
esales <- dbGetQuery(db,'SELECT * from eia_elec_sales_va_all_m') # SQL code to retrieve data from a table in the remote database
# str(esales)
esales <- as_tibble(esales) # Convert dataframe to a 'tibble' for tidyverse work
# str(esales)
# Reference: https://arrow.apache.org/docs/r/
# if(!('arrow' %in% installed.packages())) install.packages('arrow')
library(arrow)
write_feather(esales, "esales.feather")
# Close connection -- this is good practice
dbDisconnect(db)
dbUnloadDriver(db_driver)
Exploratory data analysis
str(esales)
tibble [233 × 4] (S3: tbl_df/tbl/data.frame)
$ value: num [1:233] 8282 7839 8889 9368 9209 ...
$ date : Date[1:233], format: "2020-05-01" "2020-04-01" "2020-03-01" ...
$ year : int [1:233] 2020 2020 2020 2020 2020 2019 2019 2019 2019 2019 ...
$ month: int [1:233] 5 4 3 2 1 12 11 10 9 8 ...
Provide a brief example of the data, showing how they are structured.
print(esales)
# References: https://www.tidyverse.org/, https://dplyr.tidyverse.org/
esales %>%
filter(year == 2019) %>%
filter(value > 9000) %>%
print()
esales %>%
group_by(month) %>%
summarise(mean = mean(value)) -> mean_esales_by_month
esales %>%
mutate(sales_TWh = value/1000) %>%
select(-value)
# filter(data object, condition) : syntax for filter() command
Plot the time series.
#Reference: https://ggplot2.tidyverse.org/
ggplot(data=esales, aes(x=date,y=value)) +
geom_line() + xlab(\Year\) + ylab(\Virginia monthly total electricity sales (GWh)\)

# install.packages(\tsibble\)
library(tsibble) # Reference: https://tsibble.tidyverts.org/articles/intro-tsibble.html
esales %>% as_tsibble(index = date) -> esales_tbl_ts
print(esales_tbl_ts)
# A tsibble: 233 x 4 [1D]
value date year month
<dbl> <date> <int> <int>
1 9576. 2001-01-01 2001 1
2 7820. 2001-02-01 2001 2
3 8070. 2001-03-01 2001 3
4 7153. 2001-04-01 2001 4
5 7224. 2001-05-01 2001 5
6 8264. 2001-06-01 2001 6
7 8896. 2001-07-01 2001 7
8 9404. 2001-08-01 2001 8
9 7753. 2001-09-01 2001 9
10 7272. 2001-10-01 2001 10
# … with 223 more rows
library(lubridate) # Make it easy to deal with dates
esales_tbl_ts %>% filter(month==3)
esales_tbl_ts %>% filter(month(date)==3)
esales_tbl_ts %>%
select(date, sales_GWh = value) -> elsales_tbl_ts
print(elsales_tbl_ts)
# A tsibble: 233 x 2 [1D]
date sales_GWh
<date> <dbl>
1 2001-01-01 9576.
2 2001-02-01 7820.
3 2001-03-01 8070.
4 2001-04-01 7153.
5 2001-05-01 7224.
6 2001-06-01 8264.
7 2001-07-01 8896.
8 2001-08-01 9404.
9 2001-09-01 7753.
10 2001-10-01 7272.
# … with 223 more rows
Perform and report the results of other exploratory data analysis
hist(elsales_tbl_ts$sales_GWh, breaks=40)

# install.packages(\feasts\), Reference: https://feasts.tidyverts.org/
library(feasts)
elsales_tbl_ts %>%
mutate(Month = yearmonth(date)) %>%
as_tsibble(index = Month) -> vaelsales_tbl_ts
vaelsales_tbl_ts %>% gg_season(sales_GWh, labels = \both\) + ylab(\Virginia electricity sales (GWh)\)

# install.packages('tsibbledata')
library(tsibbledata)
aus_production
aus_production %>% gg_season(Electricity)

aus_production %>% gg_season(Beer)

vaelsales_tbl_ts %>%
gg_subseries(sales_GWh)

# aus_production %>% gg_subseries(Beer)
vaelsales_tbl_ts %>% filter(month(Month) %in% c(3,6,9,12)) %>% gg_lag(sales_GWh, lags = 1:2)

vaelsales_tbl_ts %>% filter(month(Month) == 1) %>% gg_lag(sales_GWh, lags = 1:2)

vaelsales_tbl_ts %>% ACF(sales_GWh) %>% autoplot()

# if(!('fpp3' %in% installed.packages())) install.packages('fpp3')
library(fpp3)
# decompose(vaelsales_tbl_ts)
vaelsales_tbl_ts %>%
model(STL(sales_GWh ~ trend(window=21) + season(window='periodic'), robust = TRUE)) %>%
components() %>%
autoplot()

vaelsales_tbl_ts %>%
mutate(ln_sales_GWh = log(sales_GWh)) %>%
model(STL(ln_sales_GWh ~ trend(window=21) + season(window='periodic'),
robust = TRUE)) %>%
components() %>%
autoplot()

vaelsales_tbl_ts %>%
features(sales_GWh, feat_stl)
vaelsales_tbl_ts %>%
features(sales_GWh, feature_set(pkgs=\feasts\))
Example: Gross Domestic Product data
Exploratory data analysis
library(tsibbledata) # Data sets package
print(global_economy)
# A tsibble: 15,150 x 9 [1Y]
# Key: Country [263]
Country Code Year GDP Growth CPI Imports Exports Population
<fct> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Afghanistan AFG 1960 537777811. NA NA 7.02 4.13 8996351
2 Afghanistan AFG 1961 548888896. NA NA 8.10 4.45 9166764
3 Afghanistan AFG 1962 546666678. NA NA 9.35 4.88 9345868
4 Afghanistan AFG 1963 751111191. NA NA 16.9 9.17 9533954
5 Afghanistan AFG 1964 800000044. NA NA 18.1 8.89 9731361
6 Afghanistan AFG 1965 1006666638. NA NA 21.4 11.3 9938414
7 Afghanistan AFG 1966 1399999967. NA NA 18.6 8.57 10152331
8 Afghanistan AFG 1967 1673333418. NA NA 14.2 6.77 10372630
9 Afghanistan AFG 1968 1373333367. NA NA 15.2 8.90 10604346
10 Afghanistan AFG 1969 1408888922. NA NA 15.0 10.1 10854428
# … with 15,140 more rows
global_economy %>% filter(Country==\Sweden\) %>% print()
# A tsibble: 58 x 9 [1Y]
# Key: Country [1]
Country Code Year GDP Growth CPI Imports Exports Population
<fct> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Sweden SWE 1960 14842870293. NA 9.21 23.4 23.0 7484656
2 Sweden SWE 1961 16147160123. 5.68 9.41 21.7 22.3 7519998
3 Sweden SWE 1962 17511477311. 4.26 9.86 21.4 21.9 7561588
4 Sweden SWE 1963 18954132366. 5.33 10.1 21.5 21.9 7604328
5 Sweden SWE 1964 21137242561. 6.82 10.5 21.9 22.3 7661354
6 Sweden SWE 1965 23260320646. 3.82 11.0 22.5 21.9 7733853
7 Sweden SWE 1966 25302033132. 2.09 11.7 21.9 21.4 7807797
8 Sweden SWE 1967 27463409202. 3.37 12.2 21.0 21.1 7867931
9 Sweden SWE 1968 29143383491. 3.64 12.5 21.6 21.6 7912273
10 Sweden SWE 1969 31649203886. 5.01 12.8 23.0 22.8 7968072
# … with 48 more rows
global_economy %>%
filter(Country==\Sweden\) %>%
autoplot(GDP) +
ggtitle(\GDP for Sweden\) + ylab(\$US billions\)

Fitting data to simple models
global_economy %>% model(trend_model = TSLM(GDP ~ trend())) -> fit
fit
fit %>% filter(Country == \Sweden\) %>% residuals()
fit %>% filter(Country == \Sweden\) %>% residuals() %>% autoplot(.resid)

Work with ln(GDP)
global_economy %>%
filter(Country==\Sweden\) %>%
autoplot(log(GDP)) +
ggtitle(\ln(GDP) for Sweden\) + ylab(\$US billions\)

global_economy %>%
model(trend_model = TSLM(log(GDP) ~ trend())) -> logfit
logfit %>% filter(Country == \Sweden\) %>% residuals() %>% autoplot()

global_economy %>% model(trend_model = TSLM(log(GDP) ~ log(Population))) -> fit3
fit3 %>% filter(Country == \Sweden\) %>% residuals() %>% autoplot()

Producing forecasts
fit %>% forecast(h = \3 years\) -> fcast3yrs
fcast3yrs
fcast3yrs %>% filter(Country == \Sweden\, Year == 2020) %>% str()
fable [1 × 5] (S3: fbl_ts/tbl_ts/tbl_df/tbl/data.frame)
$ Country: Factor w/ 263 levels \Afghanistan\,..: 232
$ .model : chr \trend_model\
$ Year : num 2020
$ GDP : dist [1:1]
..$ 3:List of 2
.. ..$ mu : num 5.45e+11
.. ..$ sigma: num 5.34e+10
.. ..- attr(*, \class\)= chr [1:2] \dist_normal\ \dist_default\
..@ vars: chr \GDP\
$ .mean : num 5.45e+11
- attr(*, \key\)= tibble [1 × 3] (S3: tbl_df/tbl/data.frame)
..$ Country: Factor w/ 263 levels \Afghanistan\,..: 232
..$ .model : chr \trend_model\
..$ .rows : list<int> [1:1]
.. ..$ : int 1
.. ..@ ptype: int(0)
..- attr(*, \.drop\)= logi TRUE
- attr(*, \index\)= chr \Year\
..- attr(*, \ordered\)= logi TRUE
- attr(*, \index2\)= chr \Year\
- attr(*, \interval\)= interval [1:1] 1Y
..@ .regular: logi TRUE
- attr(*, \response\)= chr \GDP\
- attr(*, \dist\)= chr \GDP\
- attr(*, \model_cn\)= chr \.model\
fcast3yrs %>%
filter(Country==\Sweden\) %>%
autoplot(global_economy) +
ggtitle(\GDP for Sweden\) + ylab(\$US billions\)

Model residuals vs. forecast errors
Model residuals:
Your data: \(y_1, y_2, \ldots, y_T\)
Fitted values: \(\hat{y}_1, \hat{y}_2, \ldots, \hat{y}_T\)
Model residuals: \(e_t = y_t - \hat{y}_t\)
Forecast errors:
augment(fit)
augment(fit) %>% filter(Country == \Sweden\) %>%
ggplot(aes(x = .resid)) +
geom_histogram(bins = 20) +
ggtitle(\Histogram of residuals\)

Example: GDP, several models, several countries
library(tsibbledata) # Data sets package
nordic <- c(\Sweden\, \Denmark\, \Norway\, \Finland\)
(global_economy %>% filter(Country %in% nordic) -> nordic_economy)
nordic_economy %>% autoplot(GDP)

fitnord <- nordic_economy %>%
model(
trend_model = TSLM(GDP ~ trend()),
trend_model_ln = TSLM(log(GDP) ~ trend()),
ets = ETS(GDP ~ trend(\A\)),
arima = ARIMA(GDP)
)
fitnord
fitnord %>%
select(arima) %>%
coef()
Denmark: ARMA(1,1)
Finland: MA(2)
Norway: MA(1)
Sweden: MA(2)
nordic_economy %>%
model(arima_constrained = ARIMA(GDP ~ pdq(1,0,2))) %>% select(arima_constrained) %>% coef()
fitnord %>% coef()
fitnord %>% glance()
fitnord %>% filter(Country == \Denmark\) %>% select(arima) %>% report()
Series: GDP
Model: ARIMA(1,1,1)
Coefficients:
ar1 ma1
-0.3898 0.7240
s.e. 0.2061 0.1434
sigma^2 estimated as 2.407e+20: log likelihood=-1417.5
AIC=2840.99 AICc=2841.45 BIC=2847.12
fitnord %>%
accuracy() %>%
arrange(Country, MPE)
Statistical model
Discussion of the statistical model
Describe how the formal statistical model captures and aligns with the narrative of the data-generating process. Flag any statistical challenges raised by the data generating process, e.g. selection bias; survivorship bias; omitted variables bias, etc.
Plan for data analysis
Describe what information you wish to extract from the data. Do you wish to… estimate the values of the unobserved model parameters? create a tool for forecasting? estimate the exceedance probabilities for future realizations of \(y_t\)?
Describe your plan for getting this information. OLS regression? Some other statistical technique?
If you can: describe briefly which computational tools you will use (e.g., R), and which packages you expect to draw on.
Submission requirements
Prepare your proposal using Markdown . (You may find it useful to generate your Markdown file from some other tool, e.g. R Markdown in R Studio.) Submit your proposal by pushing it to your repo within the course organization on Github. When your proposal is ready, notify the instructor by also creating a submission for this assignment on Collab. Please also upload a PDF version of your proposal to Collab as part of your submission.
References
LS0tCnRpdGxlOiAgICAgIlByb2plY3QgUHJvcG9zYWwgSW5zdHJ1Y3Rpb25zIHdpdGggZXhhbXBsZSBjb2RlIgppbnN0aXR1dGU6ICJTWVMgNTU4MSBUaW1lIFNlcmllcyAmIEZvcmVjYXN0aW5nLCBTcHJpbmcgMjAyMSIgCmF1dGhvcjogICAgICJJbnN0cnVjdG9yOiBBcnRodXIgU21hbGwiCmRhdGU6ICAgICAgICJWZXJzaW9uIG9mIGByIFN5cy5EYXRlKClgIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIGNvZGVfZm9sZGluZzogc2hvdyAjIG9wdGlvbnM6IHNob3csIGhpZGUKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAjIGh0bWxfZG9jdW1lbnQ6CiAgIyAgICAgICBrZWVwX21kOiB5ZXMKICAjIHBkZl9kb2N1bWVudDogZGVmYXVsdApiaWJsaW9ncmFwaHk6IC9Vc2Vycy9BcnRodXIvR2l0UmVwb3MvVGVhY2hpbmcvdGltZS1zZXJpZXMvdHNlcmllcy5iaWIKbGluay1jaXRhdGlvbnM6IHllcwotLS0KCkluIHRoaXMgYXNzaWdubWVudCB5b3Ugd2lsbCBkZXZlbG9wIHlvdXIgaW5pdGlhbCBjb25jZXB0IG5vdGUgaW50byBhIGRyYWZ0IG9mIGEgZnVsbCBwcm9qZWN0IHByb3Bvc2FsLiBUcmVhdCB0aGlzIGFzc2lnbm1lbnQgYXMgYSAiZHJ5IHJ1biIgZm9yIGRldmVsb3BpbmcgYSBwcm9wb3NhbCBmb3IgYSBncmFudCBvciBmZWxsb3dzaGlwIGFwcGxpY2F0aW9uLCBvciBmb3IgeW91ciBQaC5ELiBwcm9zcGVjdHVzLgoKWW91ciBwcm9wb3NhbCBzaG91bGQgaW5jbHVkZSBhdCBsZWFzdCB0aGUgZm9sbG93aW5nIHNlY3Rpb25zIGFuZCBpbmZvcm1hdGlvbi4KCioqRnJvbnQgbWF0dGVyOioqIERlc2NyaXB0aXZlIHRpdGxlLCB5b3VyIG5hbWUsIGRhdGUsIHJlZmVyZW5jZSB0byAiU1lTIDU1ODEgVGltZSBTZXJpZXMgJiBGb3JlY2FzdGluZywgU3ByaW5nIDIwMjEiLgoKKipBYnN0cmFjdDoqKiBBIHZlcnkgYnJpZWYgc3VtbWFyeSBvZiB0aGUgcHJvamVjdC4KCiMgSW50cm9kdWN0aW9uCgpHaXZlIGEgbmFycmF0aXZlIGRlc2NyaXB0aW9uIG9mIHRoZSBwcm9ibGVtIHlvdSBhcmUgYWRkcmVzc2luZywgYW5kIHRoZSBtZXRob2RzIHlvdSB3aWxsIHVzZSB0byBhZGRyZXNzIGl0LiBQcm92aWRlIGNvbnRleHQ6CgotICAgV2hhdCBpcyB0aGUgcXVlc3Rpb24geW91IGFyZSBhdHRlbXB0aW5nIHRvIGFuc3dlcj8KLSAgIFdoeSBpcyB0aGlzIHF1ZXN0aW9uIGltcG9ydGFudD8gKFdobyBjYXJlcz8pCi0gICBIb3cgd2lsbCB5b3UgZ28gYWJvdXQgYXR0ZW1wdGluZyB0byBhbnN3ZXIgdGhpcyBxdWVzdGlvbj8KClRoaXMgd29yayBhZGRyZXNzZXMgdGhlIHF1ZXN0aW9uOiBXaHkgZG8gcGVvcGxlIG5vdCB1c2UgcHJvYmFiaWxpc3RpYyBmb3JlY2FzdHMgZm9yIGRlY2lzaW9uLW1ha2luZyBbQGNvdW5jaWxDb21wbGV0aW5nRm9yZWNhc3RDaGFyYWN0ZXJpemluZzIwMDddPwoKIyBUaGUgZGF0YSBhbmQgdGhlIGRhdGEtZ2VuZXJhdGluZyBwcm9jZXNzCgpEZXNjcmliZSB0aGUgZGF0YSBzZXQgeW91IHdpbGwgYmUgYW5hbHl6aW5nLCBhbmQgd2hlcmUgaXQgY29tZXMgZnJvbSwgaG93IGl0IHdhcyBnZW5lcmF0ZWQgYW5kIGNvbGxlY3RlZC4gSWRlbnRpZnkgdGhlIHNvdXJjZSBvZiB0aGUgZGF0YS4gR2l2ZSBhIG5hcnJhdGl2ZSBkZXNjcmlwdGlvbiBvZiB0aGUgZGF0YS1nZW5lcmF0aW5nIHByb2Nlc3M6IHRoaXMgcGllY2UgaXMgY3JpdGljYWwgLgoKU2luY2UgdGhlc2Ugd2lsbCBiZSB0aW1lIHNlcmllcyBkYXRhOiBpZGVudGlmeSB0aGUgZnJlcXVlbmN5IG9mIHRoZSBkYXRhIHNlcmllcyAoZS5nLiwgaG91cmx5LCBtb250aGx5KSwgYW5kIHRoZSBwZXJpb2Qgb2YgcmVjb3JkLgoKYGBge3Igc2V0IHVwIGNvZGluZyBlbnZpcm9ubWVudCwgaW5jbHVkZT1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KIyBsaWJyYXJ5KGRwbHlyKSAtLSBkb24ndCBuZWVkIHRoaXMgaWYgeW91IGFyZSBsb2FkaW5nIHRoZSBlbnRpcmUgJ3RpZHl2ZXJzZScgc3VpdGUKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobHVicmlkYXRlKSAjIEZvciBlYXN5IGhhbmRsaW5nIG9mIHRpbWUtaW5kZXhlZCBvYmplY3RzCgojIGlmKCEoJ2ZwcDMnICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKCkpKSBpbnN0YWxsLnBhY2thZ2VzKCdmcHAzJykKbGlicmFyeShmcHAzKQpgYGAKCmBgYHtyIG9wZW4gY29ubmVjdGlvbiB0byBkYXRhYmFzZSwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KIyBPcGVuIGNvbm5lY3Rpb24gdG8gYSByZW1vdGUgZGF0YWJhc2UKIyBNYWtlIHN1cmUgeW91ciBWUE4gbmV0d29yayBjb25uZWN0aW9uIGlzIGFjdGl2ZSBpZiBuZWVkZWQhCgojIGlmKCEoJ1JQb3N0Z3JlU1FMJyAlaW4lIGluc3RhbGxlZC5wYWNrYWdlcygpKSkgaW5zdGFsbC5wYWNrYWdlcygnUlBvc3RncmVTUUwnKQpsaWJyYXJ5KFJQb3N0Z3JlU1FMKQoKIyAibXlfcG9zdGdyZXNfY3JlZGVudGlhbHMuUiIgY29udGFpbnMgdGhlIGxvZy1pbiBpbmZvcm1hdGlvbgpzb3VyY2UoIi9Vc2Vycy9BcnRodXIvR2l0UmVwb3MvVGVhY2hpbmcvbXlfcG9zdGdyZXNfZGJfY3JlZGVudGlhbHMuUiIpCgojIE9wZW4gY29ubmVjdGlvbgpkYl9kcml2ZXIgPC0gZGJEcml2ZXIoIlBvc3RncmVTUUwiKQpkYiA8LSBkYkNvbm5lY3QoZGJfZHJpdmVyLHVzZXI9dXNlciwgcGFzc3dvcmQ9cGFzc3dvcmQsZGJuYW1lPSJwb3N0Z3JlcyIsIGhvc3Q9aG9zdCkKcm0ocGFzc3dvcmQpIAoKIyBjaGVjayB0aGUgY29ubmVjdGlvbjogSWYgZnVuY3Rpb24gcmV0dXJucyB2YWx1ZSBUUlVFLCB0aGUgY29ubmVjdGlvbiBpcyB3b3JraW5nCmRiRXhpc3RzVGFibGUoZGIsICJtZXRhZGF0YSIpCmBgYAoKYGBge3IgcmV0cmlldmUgZGF0YSBmcm9tIGRiLCBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQplc2FsZXMgPC0gZGJHZXRRdWVyeShkYiwnU0VMRUNUICogZnJvbSBlaWFfZWxlY19zYWxlc192YV9hbGxfbScpICMgU1FMIGNvZGUgdG8gcmV0cmlldmUgZGF0YSBmcm9tIGEgdGFibGUgaW4gdGhlIHJlbW90ZSBkYXRhYmFzZQojIHN0cihlc2FsZXMpCmVzYWxlcyA8LSBhc190aWJibGUoZXNhbGVzKSAjIENvbnZlcnQgZGF0YWZyYW1lIHRvIGEgJ3RpYmJsZScgZm9yIHRpZHl2ZXJzZSB3b3JrCiMgc3RyKGVzYWxlcykKYGBgCgpgYGB7ciBzYXZlIGRhdGEgaW4gQXBhY2hlIEFycm93IGZvcm1hdCwgZXZhbD1GQUxTRX0KIyBSZWZlcmVuY2U6IGh0dHBzOi8vYXJyb3cuYXBhY2hlLm9yZy9kb2NzL3IvCiMgaWYoISgnYXJyb3cnICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKCkpKSBpbnN0YWxsLnBhY2thZ2VzKCdhcnJvdycpCmxpYnJhcnkoYXJyb3cpCndyaXRlX2ZlYXRoZXIoZXNhbGVzLCAiZXNhbGVzLmZlYXRoZXIiKQpgYGAKCmBgYHtyIGNsb3NlIGRiIGNvbm5lY3Rpb24sIGV2YWw9RkFMU0V9CiMgQ2xvc2UgY29ubmVjdGlvbiAtLSB0aGlzIGlzIGdvb2QgcHJhY3RpY2UKZGJEaXNjb25uZWN0KGRiKQpkYlVubG9hZERyaXZlcihkYl9kcml2ZXIpCmBgYAoKIyBFeHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzCgpgYGB7ciByZWFkIGluIGRhdGF9CmxpYnJhcnkoYXJyb3cpCmVzYWxlcyA8LSByZWFkX2ZlYXRoZXIoImVzYWxlcy5mZWF0aGVyIikKCnN0cihlc2FsZXMpCmBgYAoKIyMgUHJvdmlkZSBhIGJyaWVmIGV4YW1wbGUgb2YgdGhlIGRhdGEsIHNob3dpbmcgaG93IHRoZXkgYXJlIHN0cnVjdHVyZWQuCgpgYGB7ciBwcmludCB0aGUgZGF0YSBhcyBhIHRhYmxlfQpwcmludChlc2FsZXMpCmBgYAoKYGBge3IgdXNlIHRpZHl2ZXJzZSBzeW50YXggdG8gcGVyZm9ybSBzb21lIHNpbXBsZSBkYXRhIG1hbmlwdWxhdGlvbnN9CiMgUmVmZXJlbmNlczogaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy8sIGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZy8KCmVzYWxlcyAlPiUKICBmaWx0ZXIoeWVhciA9PSAyMDE5KSAlPiUKICBmaWx0ZXIodmFsdWUgPiA5MDAwKSAlPiUKICBwcmludCgpCgplc2FsZXMgJT4lCiAgZ3JvdXBfYnkobW9udGgpICU+JQogIHN1bW1hcmlzZShtZWFuID0gbWVhbih2YWx1ZSkpIC0+IG1lYW5fZXNhbGVzX2J5X21vbnRoCgplc2FsZXMgJT4lCiAgbXV0YXRlKHNhbGVzX1RXaCA9IHZhbHVlLzEwMDApICU+JQogIHNlbGVjdCgtdmFsdWUpCiAgCiMgZmlsdGVyKGRhdGEgb2JqZWN0LCBjb25kaXRpb24pIDogc3ludGF4IGZvciBmaWx0ZXIoKSBjb21tYW5kCmBgYAoKIyMgUGxvdCB0aGUgdGltZSBzZXJpZXMuCgpgYGB7ciB1c2UgZ2dwbG90MiB0byBnZW5lcmF0ZSBhIHBsb3R9CiNSZWZlcmVuY2U6IGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnLwoKZ2dwbG90KGRhdGE9ZXNhbGVzLCBhZXMoeD1kYXRlLHk9dmFsdWUpKSArIAogIGdlb21fbGluZSgpICsgeGxhYigiWWVhciIpICsgeWxhYigiVmlyZ2luaWEgbW9udGhseSB0b3RhbCBlbGVjdHJpY2l0eSBzYWxlcyAoR1doKSIpCgpgYGAKCmBgYHtyfQojIGluc3RhbGwucGFja2FnZXMoInRzaWJibGUiKQpsaWJyYXJ5KHRzaWJibGUpICMgUmVmZXJlbmNlOiBodHRwczovL3RzaWJibGUudGlkeXZlcnRzLm9yZy9hcnRpY2xlcy9pbnRyby10c2liYmxlLmh0bWwKCmVzYWxlcyAlPiUgYXNfdHNpYmJsZShpbmRleCA9IGRhdGUpIC0+IGVzYWxlc190YmxfdHMKCnByaW50KGVzYWxlc190YmxfdHMpCmBgYAoKYGBge3J9CmxpYnJhcnkobHVicmlkYXRlKSAjIE1ha2UgaXQgZWFzeSB0byBkZWFsIHdpdGggZGF0ZXMKCmVzYWxlc190YmxfdHMgJT4lIGZpbHRlcihtb250aD09MykKCmVzYWxlc190YmxfdHMgJT4lIGZpbHRlcihtb250aChkYXRlKT09MykKCmVzYWxlc190YmxfdHMgJT4lCiAgc2VsZWN0KGRhdGUsIHNhbGVzX0dXaCA9IHZhbHVlKSAtPiBlbHNhbGVzX3RibF90cwoKcHJpbnQoZWxzYWxlc190YmxfdHMpCmBgYAoKIyMgUGVyZm9ybSBhbmQgcmVwb3J0IHRoZSByZXN1bHRzIG9mIG90aGVyIGV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMKCmBgYHtyIG1ha2UgYSBoaXN0b2dyYW0gb2YgdGhlIGRhdGF9CgpoaXN0KGVsc2FsZXNfdGJsX3RzJHNhbGVzX0dXaCwgYnJlYWtzPTQwKQpgYGAKCmBgYHtyfQojIGluc3RhbGwucGFja2FnZXMoImZlYXN0cyIpLCBSZWZlcmVuY2U6IGh0dHBzOi8vZmVhc3RzLnRpZHl2ZXJ0cy5vcmcvCmxpYnJhcnkoZmVhc3RzKQoKZWxzYWxlc190YmxfdHMgJT4lIAogIG11dGF0ZShNb250aCA9IHllYXJtb250aChkYXRlKSkgJT4lIAogIGFzX3RzaWJibGUoaW5kZXggPSBNb250aCkgLT4gdmFlbHNhbGVzX3RibF90cwoKCnZhZWxzYWxlc190YmxfdHMgJT4lIGdnX3NlYXNvbihzYWxlc19HV2gsIGxhYmVscyA9ICJib3RoIikgKyB5bGFiKCJWaXJnaW5pYSBlbGVjdHJpY2l0eSBzYWxlcyAoR1doKSIpCmBgYAoKYGBge3J9CiMgaW5zdGFsbC5wYWNrYWdlcygndHNpYmJsZWRhdGEnKQpsaWJyYXJ5KHRzaWJibGVkYXRhKQoKYXVzX3Byb2R1Y3Rpb24KCmF1c19wcm9kdWN0aW9uICU+JSBnZ19zZWFzb24oRWxlY3RyaWNpdHkpCgphdXNfcHJvZHVjdGlvbiAlPiUgZ2dfc2Vhc29uKEJlZXIpCgoKYGBgCgpgYGB7cn0KdmFlbHNhbGVzX3RibF90cyAlPiUgCiAgZ2dfc3Vic2VyaWVzKHNhbGVzX0dXaCkKCiMgYXVzX3Byb2R1Y3Rpb24gJT4lIGdnX3N1YnNlcmllcyhCZWVyKQpgYGAKCmBgYHtyIHBsb3QgbGFnZ2VkIHZhbHVlc30KdmFlbHNhbGVzX3RibF90cyAgJT4lIGZpbHRlcihtb250aChNb250aCkgJWluJSBjKDMsNiw5LDEyKSkgJT4lIGdnX2xhZyhzYWxlc19HV2gsIGxhZ3MgPSAxOjIpCgp2YWVsc2FsZXNfdGJsX3RzICAlPiUgZmlsdGVyKG1vbnRoKE1vbnRoKSA9PSAxKSAlPiUgZ2dfbGFnKHNhbGVzX0dXaCwgbGFncyA9IDE6MikKYGBgCgpgYGB7cn0KdmFlbHNhbGVzX3RibF90cyAlPiUgQUNGKHNhbGVzX0dXaCkgJT4lIGF1dG9wbG90KCkKYGBgCgpgYGB7ciBwZXJmb3JtIGF1dG9tYXRlZCB0aW1lIHNlcmllcyBkZWNvbXBvc2l0aW9ufQoKCiMgZGVjb21wb3NlKHZhZWxzYWxlc190YmxfdHMpCmBgYAoKYGBge3IgcGVyZm9ybSBhZGRpdGl2ZSBTVEwgZGVjb21wb3NpdGlvbiBvZiB0aGUgVkEgZWxlY3RyaWNpdHkgc2FsZXMgdGltZSBzZXJpZXN9CnZhZWxzYWxlc190YmxfdHMgJT4lCiAgbW9kZWwoU1RMKHNhbGVzX0dXaCB+IHRyZW5kKHdpbmRvdz0yMSkgKyBzZWFzb24od2luZG93PSdwZXJpb2RpYycpLCByb2J1c3QgPSBUUlVFKSkgJT4lCiAgY29tcG9uZW50cygpICU+JQogIGF1dG9wbG90KCkKYGBgCgpgYGB7ciBwZXJmb3JtIG11bHRpcGxpY2F0aXZlIFNUTCBkZWNvbXBvc2l0aW9uIG9mIHRoZSBWQSBlbGVjdHJpY2l0eSBzYWxlcyB0aW1lIHNlcmllc30KdmFlbHNhbGVzX3RibF90cyAlPiUKICBtdXRhdGUobG5fc2FsZXNfR1doID0gbG9nKHNhbGVzX0dXaCkpICU+JQogIG1vZGVsKFNUTChsbl9zYWxlc19HV2ggfiB0cmVuZCh3aW5kb3c9MjEpICsgc2Vhc29uKHdpbmRvdz0ncGVyaW9kaWMnKSwKICAgIHJvYnVzdCA9IFRSVUUpKSAlPiUKICBjb21wb25lbnRzKCkgJT4lCiAgYXV0b3Bsb3QoKQpgYGAKCmBgYHtyfQp2YWVsc2FsZXNfdGJsX3RzICU+JQogIGZlYXR1cmVzKHNhbGVzX0dXaCwgZmVhdF9zdGwpCmBgYAoKYGBge3J9CnZhZWxzYWxlc190YmxfdHMgJT4lCiAgZmVhdHVyZXMoc2FsZXNfR1doLCBmZWF0dXJlX3NldChwa2dzPSJmZWFzdHMiKSkKYGBgCgojIEV4YW1wbGU6IEdyb3NzIERvbWVzdGljIFByb2R1Y3QgZGF0YQoKIyMgRXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcwoKYGBge3J9CmxpYnJhcnkodHNpYmJsZWRhdGEpICMgRGF0YSBzZXRzIHBhY2thZ2UKCnByaW50KGdsb2JhbF9lY29ub215KQpgYGAKCmBgYHtyfQpnbG9iYWxfZWNvbm9teSAlPiUgZmlsdGVyKENvdW50cnk9PSJTd2VkZW4iKSAlPiUgcHJpbnQoKQpgYGAKCmBgYHtyfQpnbG9iYWxfZWNvbm9teSAlPiUKICBmaWx0ZXIoQ291bnRyeT09IlN3ZWRlbiIpICU+JQogIGF1dG9wbG90KEdEUCkgKwogIGdndGl0bGUoIkdEUCBmb3IgU3dlZGVuIikgKyB5bGFiKCIkVVMgYmlsbGlvbnMiKQpgYGAKCiMjIEZpdHRpbmcgZGF0YSB0byBzaW1wbGUgbW9kZWxzCgpgYGB7cn0KZ2xvYmFsX2Vjb25vbXkgJT4lIG1vZGVsKHRyZW5kX21vZGVsID0gVFNMTShHRFAgfiB0cmVuZCgpKSkgLT4gZml0CgpmaXQKCgpgYGAKCmBgYHtyfQpmaXQgJT4lIGZpbHRlcihDb3VudHJ5ID09ICJTd2VkZW4iKSAlPiUgcmVzaWR1YWxzKCkKYGBgCgpgYGB7cn0KCmZpdCAlPiUgZmlsdGVyKENvdW50cnkgPT0gIlN3ZWRlbiIpICU+JSByZXNpZHVhbHMoKSAlPiUgYXV0b3Bsb3QoLnJlc2lkKQpgYGAKCiMjIyBXb3JrIHdpdGggbG4oR0RQKQoKYGBge3J9Cmdsb2JhbF9lY29ub215ICU+JQogIGZpbHRlcihDb3VudHJ5PT0iU3dlZGVuIikgJT4lCiAgYXV0b3Bsb3QobG9nKEdEUCkpICsKICBnZ3RpdGxlKCJsbihHRFApIGZvciBTd2VkZW4iKSArIHlsYWIoIiRVUyBiaWxsaW9ucyIpCmBgYAoKYGBge3J9Cmdsb2JhbF9lY29ub215ICU+JQogIG1vZGVsKHRyZW5kX21vZGVsID0gVFNMTShsb2coR0RQKSB+IHRyZW5kKCkpKSAtPiBsb2dmaXQKYGBgCgpgYGB7cn0KbG9nZml0ICU+JSBmaWx0ZXIoQ291bnRyeSA9PSAiU3dlZGVuIikgJT4lIHJlc2lkdWFscygpICU+JSBhdXRvcGxvdCgpCmBgYAoKYGBge3J9Cmdsb2JhbF9lY29ub215ICU+JSBtb2RlbCh0cmVuZF9tb2RlbCA9IFRTTE0obG9nKEdEUCkgfiBsb2coUG9wdWxhdGlvbikpKSAtPiBmaXQzCgpmaXQzICU+JSBmaWx0ZXIoQ291bnRyeSA9PSAiU3dlZGVuIikgJT4lIHJlc2lkdWFscygpICU+JSBhdXRvcGxvdCgpCgpgYGAKCiMgUHJvZHVjaW5nIGZvcmVjYXN0cwoKYGBge3J9CmZpdCAlPiUgZm9yZWNhc3QoaCA9ICIzIHllYXJzIikgLT4gZmNhc3QzeXJzCgpmY2FzdDN5cnMKCmBgYAoKYGBge3J9CgpmY2FzdDN5cnMgJT4lIGZpbHRlcihDb3VudHJ5ID09ICJTd2VkZW4iLCBZZWFyID09IDIwMjApICU+JSBzdHIoKQpgYGAKCmBgYHtyIHZpc3VhbGl6ZSBmb3JlY2FzdHN9CmZjYXN0M3lycyAlPiUgCiAgZmlsdGVyKENvdW50cnk9PSJTd2VkZW4iKSAlPiUKICBhdXRvcGxvdChnbG9iYWxfZWNvbm9teSkgKwogIGdndGl0bGUoIkdEUCBmb3IgU3dlZGVuIikgKyB5bGFiKCIkVVMgYmlsbGlvbnMiKQpgYGAKCiMjIE1vZGVsIHJlc2lkdWFscyB2cy4gZm9yZWNhc3QgZXJyb3JzCgpNb2RlbCByZXNpZHVhbHM6CgpZb3VyIGRhdGE6ICR5XzEsIHlfMiwgXGxkb3RzLCB5X1QkCgpGaXR0ZWQgdmFsdWVzOiAkXGhhdHt5fV8xLCBcaGF0e3l9XzIsIFxsZG90cywgXGhhdHt5fV9UJAoKTW9kZWwgcmVzaWR1YWxzOiAkZV90ID0geV90IC0gXGhhdHt5fV90JAoKRm9yZWNhc3QgZXJyb3JzOgoKYGBge3J9CmF1Z21lbnQoZml0KQpgYGAKCmBgYHtyfQphdWdtZW50KGZpdCkgJT4lIGZpbHRlcihDb3VudHJ5ID09ICJTd2VkZW4iKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSAucmVzaWQpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDIwKSArCiAgZ2d0aXRsZSgiSGlzdG9ncmFtIG9mIHJlc2lkdWFscyIpCmBgYAoKIyMgQXJlIHRoZSBtb2RlbCByZXNpZHVhbHMgYXV0by1jb3JyZWxhdGVkPwoKYGBge3J9CmF1Z21lbnQoZml0KSAlPiUgZmlsdGVyKENvdW50cnkgPT0gIlN3ZWRlbiIpIC0+IGF1Z1N3ZWRlbgoKYXVnU3dlZGVuICU+JQogIEFDRigucmVzaWQpICU+JQogIGF1dG9wbG90KCkgKyBnZ3RpdGxlKCJBQ0Ygb2YgcmVzaWR1YWxzIikKYGBgCgpgYGB7cn0KYXVnbWVudChmaXQzKSAlPiUgZmlsdGVyKENvdW50cnkgPT0gIlN3ZWRlbiIpIC0+IGF1Z1N3ZWRlbjMKCmF1Z1N3ZWRlbjMgJT4lCiAgQUNGKC5yZXNpZCkgJT4lCiAgYXV0b3Bsb3QoKSArIGdndGl0bGUoIkFDRiBvZiByZXNpZHVhbHMiKQpgYGAKCgojIEV4YW1wbGU6IEdEUCwgc2V2ZXJhbCBtb2RlbHMsIHNldmVyYWwgY291bnRyaWVzCgoKYGBge3J9CmxpYnJhcnkodHNpYmJsZWRhdGEpICMgRGF0YSBzZXRzIHBhY2thZ2UKCm5vcmRpYyA8LSBjKCJTd2VkZW4iLCAiRGVubWFyayIsICJOb3J3YXkiLCAiRmlubGFuZCIpCgooZ2xvYmFsX2Vjb25vbXkgJT4lIGZpbHRlcihDb3VudHJ5ICVpbiUgbm9yZGljKSAtPiBub3JkaWNfZWNvbm9teSkKCmBgYAoKYGBge3J9Cm5vcmRpY19lY29ub215ICU+JSBhdXRvcGxvdChHRFApCmBgYAoKYGBge3J9CmZpdG5vcmQgPC0gbm9yZGljX2Vjb25vbXkgJT4lCiAgbW9kZWwoCiAgICB0cmVuZF9tb2RlbCA9IFRTTE0oR0RQIH4gdHJlbmQoKSksCiAgICB0cmVuZF9tb2RlbF9sbiA9IFRTTE0obG9nKEdEUCkgfiB0cmVuZCgpKSwKICAgIGV0cyA9IEVUUyhHRFAgfiB0cmVuZCgiQSIpKSwKICAgIGFyaW1hID0gQVJJTUEoR0RQKQogICkKCmZpdG5vcmQKYGBgCgpgYGB7cn0KZml0bm9yZCAlPiUKICBzZWxlY3QoYXJpbWEpICU+JQogIGNvZWYoKQpgYGAKCgpEZW5tYXJrOiBBUk1BKDEsMSkKCkZpbmxhbmQ6IE1BKDIpCgpOb3J3YXk6IE1BKDEpCgpTd2VkZW46IE1BKDIpCgpgYGB7cn0Kbm9yZGljX2Vjb25vbXkgJT4lCiAgbW9kZWwoYXJpbWFfY29uc3RyYWluZWQgPSBBUklNQShHRFAgfiBwZHEoMSwwLDIpKSkgJT4lIHNlbGVjdChhcmltYV9jb25zdHJhaW5lZCkgJT4lIGNvZWYoKQpgYGAKCmBgYHtyfQpmaXRub3JkICU+JSBjb2VmKCkgCmBgYAoKYGBge3J9CmZpdG5vcmQgJT4lICBnbGFuY2UoKSAgCmBgYAoKYGBge3J9CmZpdG5vcmQgJT4lIGZpbHRlcihDb3VudHJ5ID09ICJEZW5tYXJrIikgJT4lIHNlbGVjdChhcmltYSkgJT4lIHJlcG9ydCgpCmBgYAoKYGBge3J9CmZpdG5vcmQgJT4lCiAgYWNjdXJhY3koKSAlPiUKICBhcnJhbmdlKENvdW50cnksIE1QRSkKYGBgCgoKIyBTdGF0aXN0aWNhbCBtb2RlbAoKIyMgRm9ybWFsIG1vZGVsIG9mIGRhdGEtZ2VuZXJhdGluZyBwcm9jZXNzCgpXcml0ZSBkb3duIGFuIGVxdWF0aW9uIChvciBzZXQgb2YgZXF1YXRpb25zKSB0aGF0IHJlcHJlc2VudCB0aGUgZGF0YS1nZW5lcmF0aW5nIHByb2Nlc3MgZm9ybWFsbHkuCgpGb3IgdGhlIGVsZWN0cmljaXR5IHNhbGVzIGRhdGEsIG1heWJlIHRoZSBwcm9jZXNzIGxvb2tzIGxpa2U6CgokJCB5X3QgPSBUcmVuZF90IFggU2Vhc29uYWxfdCBYIFJlc2lkdWFsX3QgJCQgJCQgeV90ID0gXGJldGFfMCArIFxiZXRhXzEgdCArIFxiZXRhXzIgbSArIFx2YXJlcHNpbG9uX3QgJCQKCmBgYHtyLCBldmFsPUZBTFNFfQojIEVUUyBmb3JlY2FzdHMKVVNBY2NEZWF0aHMgJT4lCiAgZXRzKCkgJT4lCiAgZm9yZWNhc3QoKSAlPiUKICBhdXRvcGxvdCgpCmBgYAoKYGBge3IsIGV2YWw9RkFMU0V9CnN0cih0YXlsb3IpCnBsb3QodGF5bG9yKQpgYGAKCklmIGFwcGxpY2FibGU6IGRlc2NyaWJlIGFueSB0cmFuc2Zvcm1hdGlvbnMgb2YgdGhlIGRhdGEgKGUuZy4sIGRpZmZlcmVuY2luZywgdGFraW5nIGxvZ3MpIHlvdSBuZWVkIHRvIG1ha2UgdG8gZ2V0IHRoZSBkYXRhIGludG8gYSBmb3JtIChlLmcuLCBsaW5lYXIpIHJlYWR5IGZvciBudW1lcmljYWwgYW5hbHlzaXMuCgpXaGF0IGtpbmQgb2YgcHJvY2VzcyBpcyBpdD8gJEFSKHApJD8gV2hpdGUgbm9pc2Ugd2l0aCBkcmlmdD8gU29tZXRoaW5nIGVsc2U/CgpXcml0ZSBkb3duIGFuIGVxdWF0aW9uIGV4cHJlc3NpbmcgZWFjaCByZWFsaXphdGlvbiBvZiB0aGUgc3RvY2hhc3RpYyBwcm9jZXNzICR5X3QkIGFzIGEgZnVuY3Rpb24gb2Ygb3RoZXIgb2JzZXJ2ZWQgZGF0YSAod2hpY2ggY291bGQgaW5jbHVkZSBsYWdnZWQgdmFsdWVzIG9mICR5JCksIHVub2JzZXJ2ZWQgcGFyYW1ldGVycyAoJFxiZXRhJCksIGFuZCBhbiBlcnJvciB0ZXJtICgkXHZhcmVwc2lsb25fdCQpLiBFeDoKCiQkeSA9IFhcY2RvdFxiZXRhICsgXHZhcmVwc2lsb24kJCBBZGQgYSBtb2RlbCBvZiB0aGUgZXJyb3IgcHJvY2Vzcy4gRXg6ICRcdmFyZXBzaWxvbiBcc2ltIE4oMCwgXHNpZ21hXjIgSV9UKSQuCgojIyBEaXNjdXNzaW9uIG9mIHRoZSBzdGF0aXN0aWNhbCBtb2RlbAoKRGVzY3JpYmUgaG93IHRoZSBmb3JtYWwgc3RhdGlzdGljYWwgbW9kZWwgY2FwdHVyZXMgYW5kIGFsaWducyB3aXRoIHRoZSBuYXJyYXRpdmUgb2YgdGhlIGRhdGEtZ2VuZXJhdGluZyBwcm9jZXNzLiBGbGFnIGFueSBzdGF0aXN0aWNhbCBjaGFsbGVuZ2VzIHJhaXNlZCBieSB0aGUgZGF0YSBnZW5lcmF0aW5nIHByb2Nlc3MsIGUuZy4gc2VsZWN0aW9uIGJpYXM7IHN1cnZpdm9yc2hpcCBiaWFzOyBvbWl0dGVkIHZhcmlhYmxlcyBiaWFzLCBldGMuCgojIFBsYW4gZm9yIGRhdGEgYW5hbHlzaXMKCkRlc2NyaWJlIHdoYXQgaW5mb3JtYXRpb24geW91IHdpc2ggdG8gZXh0cmFjdCBmcm9tIHRoZSBkYXRhLiBEbyB5b3Ugd2lzaCB0by4uLiBlc3RpbWF0ZSB0aGUgdmFsdWVzIG9mIHRoZSB1bm9ic2VydmVkIG1vZGVsIHBhcmFtZXRlcnM/IGNyZWF0ZSBhIHRvb2wgZm9yIGZvcmVjYXN0aW5nPyBlc3RpbWF0ZSB0aGUgZXhjZWVkYW5jZSBwcm9iYWJpbGl0aWVzIGZvciBmdXR1cmUgcmVhbGl6YXRpb25zIG9mICR5X3QkPwoKRGVzY3JpYmUgeW91ciBwbGFuIGZvciBnZXR0aW5nIHRoaXMgaW5mb3JtYXRpb24uIE9MUyByZWdyZXNzaW9uPyBTb21lIG90aGVyIHN0YXRpc3RpY2FsIHRlY2huaXF1ZT8KCklmIHlvdSBjYW46IGRlc2NyaWJlIGJyaWVmbHkgd2hpY2ggY29tcHV0YXRpb25hbCB0b29scyB5b3Ugd2lsbCB1c2UgKGUuZy4sIFIpLCBhbmQgd2hpY2ggcGFja2FnZXMgeW91IGV4cGVjdCB0byBkcmF3IG9uLgoKIyBTdWJtaXNzaW9uIHJlcXVpcmVtZW50cwoKUHJlcGFyZSB5b3VyIHByb3Bvc2FsIHVzaW5nIE1hcmtkb3duIC4gKFlvdSBtYXkgZmluZCBpdCB1c2VmdWwgdG8gZ2VuZXJhdGUgeW91ciBNYXJrZG93biBmaWxlIGZyb20gc29tZSBvdGhlciB0b29sLCBlLmcuIFIgTWFya2Rvd24gaW4gUiBTdHVkaW8uKSBTdWJtaXQgeW91ciBwcm9wb3NhbCBieSBwdXNoaW5nIGl0IHRvIHlvdXIgcmVwbyB3aXRoaW4gdGhlIGNvdXJzZSBvcmdhbml6YXRpb24gb24gR2l0aHViLiBXaGVuIHlvdXIgcHJvcG9zYWwgaXMgcmVhZHksIG5vdGlmeSB0aGUgaW5zdHJ1Y3RvciBieSBhbHNvIGNyZWF0aW5nIGEgc3VibWlzc2lvbiBmb3IgdGhpcyBhc3NpZ25tZW50IG9uIENvbGxhYi4gUGxlYXNlIGFsc28gdXBsb2FkIGEgUERGIHZlcnNpb24gb2YgeW91ciBwcm9wb3NhbCB0byBDb2xsYWIgYXMgcGFydCBvZiB5b3VyIHN1Ym1pc3Npb24uCgojIENvbW1lbnQKCkRlcGVuZGluZyBvbiB5b3VyIHByaW9yIGV4cGVyaWVuY2UsIHlvdSBtYXkgZmluZCB0aGlzIGFzc2lnbm1lbnQgY2hhbGxlbmdpbmcuIFRyZWF0IHRoaXMgYXNzaWdubWVudCBhcyBhbiBvcHBvcnR1bml0eSB0byBtYWtlIHByb2dyZXNzIG9uIHlvdXIgb3duIHJlc2VhcmNoIHByb2dyYW0uIE1ha2UgeW91ciBwcm9wb3NhbCBhcyBjb21wbGV0ZSBhcyB5b3UgY2FuLiBCdXQgbm90ZSB0aGF0IHRoaXMgYXNzaWdubWVudCBpcyBtZXJlbHkgdGhlIEZpcnN0IERyYWZ0LiBZb3Ugd2lsbCBoYXZlIG1vcmUgb3Bwb3J0dW5pdHkgdG8gcmVmaW5lIHlvdXIgd29yayBvdmVyIHRoZSBuZXh0IHR3byBtb250aHMsIGluIGNvbnN1bHRhdGlvbiB3aXRoIHRoZSBpbnN0cnVjdG9yLCB5b3VyIGFkdmlzb3IsIGFuZCB5b3VyIGNsYXNzbWF0ZXMuCgojIFJlZmVyZW5jZXMK